package com.robaone.gwt.jsonp.client;

import java.util.HashMap;
import java.util.Vector;

import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.core.client.JsArray;
import com.google.gwt.http.client.Request;
import com.google.gwt.http.client.RequestBuilder;
import com.google.gwt.http.client.RequestCallback;
import com.google.gwt.http.client.RequestException;
import com.google.gwt.http.client.Response;
import com.google.gwt.http.client.URL;
import com.google.gwt.json.client.JSONArray;
import com.google.gwt.json.client.JSONBoolean;
import com.google.gwt.json.client.JSONNumber;
import com.google.gwt.json.client.JSONObject;
import com.google.gwt.json.client.JSONString;
import com.google.gwt.json.client.JSONValue;

abstract public class JsonHandler<D extends JavaScriptObject> {
	/**
	 * Handle the response to the request for stock data from a remote server.
	 */
	public void handleJsonResponse(JavaScriptObject jso) {
		
		if (jso == null) {
			this.handleFailure(new Exception("Cannot parse json"));
			return;
		}
		DSResponseManager<D> man = new DSResponseManager<D>();
		DSResponse<D> result = man.eval(jso);
		try{
			if(result.getStatus() == 0){
				this.handleSuccess(result.getData());
			}else{
				DSError errors = result.getErrors();
				this.handleErrors(errors);
			}
		}catch(Exception e){
			this.handleFailure(e);
		}
	}

	abstract public void handleFailure(Exception e);

	abstract public void handleErrors(DSError errors);

	abstract public void handleSuccess(JsArray<D> data);

	@SuppressWarnings({ "unchecked" })
	public static JSONValue createJSONObject(Object o) {
		JSONValue retval = null;
		if(o instanceof JSONValue){
			retval = (JSONValue)o;
		}else if(o instanceof HashMap){
			HashMap query = (HashMap)o;
			retval = new JSONObject();
			for(int i = 0;i < query.keySet().size();i++){
				Object key = query.keySet().toArray(new String[0])[i];
				Object value = query.get(key);
				JSONValue jv = JsonHandler.createJSONObject(value);
				((JSONObject)retval).put(key.toString(), jv);
			}
		}else if(o instanceof Vector){
			retval = new JSONArray();
			Vector v = (Vector)o;
			for(int i = 0; i < v.size();i++){
				Object value = v.get(i);
				((JSONArray)retval).set(retval.isArray().size(), JsonHandler.createJSONObject(value));
			}
		}else if(o instanceof String){
			retval = new JSONString(o.toString());
		}else if(o instanceof Integer){
			retval = new JSONNumber((Integer)o);
		}else if(o instanceof Long){
			retval = new JSONNumber((Long)o);
		}else if(o instanceof Double){
			retval = new JSONNumber((Double)o);
		}else if(o instanceof Float){
			retval = new JSONNumber((Float)o);
		}else if(o instanceof Boolean){
			retval = JSONBoolean.getInstance((Boolean)o);
		}
		return retval;
	}
	@SuppressWarnings("unchecked")
	public static String buildFetch(String url, String table,String fields,String query,Vector parameters) {
		url += "?method=fetch&query=";
		HashMap<String,Object> q = new HashMap<String,Object>();
		q.put("table", table);
		q.put("fields", fields);
		q.put("query", query);
		q.put("params",parameters);
		JSONValue o = JsonHandler.createJSONObject(q);
		url += URL.encode(o.toString());
		return url+"&callback=";
	}
	
	public static String buildPut(String url, String table,JSONValue jo){
		url += "?method=put";
		url += "&table="+URL.encode(table);
		url += "&do="+URL.encode(jo.toString());
		return url + "&callback=";
	}
	
	public static String buildGet(String url,String table,String primarykey){
		url += "?method=get";
		url += "&table="+URL.encode(table);
		url += "&id="+URL.encode(primarykey);
		return url + "&callback=";
	}
	
	public static String buildDelete(String url,String table,String primarykey){
		url += "?method=delete";
		url += "&table="+URL.encode(table);
		url += "&id="+URL.encode(primarykey);
		return url + "&callback=";
	}
	@SuppressWarnings("unchecked")
	public static void getJson(String fetchquery,
			final JsonHandler handler) {
		RequestBuilder request = new RequestBuilder(RequestBuilder.GET,fetchquery);
		try {
			request.sendRequest("", new RequestCallback(){

				@Override
				public void onError(Request request, Throwable exception) {
					handler.handleFailure(new Exception(exception));
				}

				@Override
				public void onResponseReceived(Request request, Response response) {
					if(response.getStatusCode() != 200){
						handler.handleFailure(new Exception("Http error: "+response.getStatusCode()+ " "+response.getStatusText()));
					}else{
						try{
						String json = response.getText();
						DSResponseManager man = new DSResponseManager();
						DSResponse dsr = man.eval(json);
						if(dsr.getStatus() == 0){
							JsArray data = dsr.getData();
							handler.handleSuccess(data);
						}else{
							handler.handleErrors(dsr.getErrors());
						}
						}catch(Exception e){
							handler.handleFailure(e);
						}
					}
				}
				
			});
		} catch (RequestException e) {
			handler.handleFailure(e);
		}
	}
}
